﻿// <copyright file="ItemPropertiesDialog.xaml.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2008-2009 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2008-02-18</date>
// <summary>OpenWPFChart library. Dialog to view/edit Chart Item Properties.</summary>
// <revision>$Id$</revision>

using System;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; // For PropertyChangedEventArgs
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using OpenWPFChart.Parts;

namespace OpenWPFChart.Helpers
{
	/// <summary>
	/// Dialog to view/edit Chart Item Properties.
	/// Interaction logic for ItemPropertiesDialog.xaml
	/// </summary>
	public partial class ItemPropertiesDialog : Window, INotifyPropertyChanged
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="ItemPropertiesDialog"/> class.
		/// </summary>
		/// <param name="itemDataView">ItemDataView.</param>
		public ItemPropertiesDialog(ItemDataView itemDataView)
		{
			if (itemDataView == null)
				throw new ArgumentNullException("itemDataView");
			
			InitializeComponent();

			// Get current InterpolatedVisual in the itemDataView.VisualCue.
			object visualCue = itemDataView.VisualCue;
			if (visualCue is Type && (visualCue as Type).IsDefined(typeof(InterpolatedAttribute), false))
			{
				interpolatedVisual = visualCue as Type;
			}
			else if (visualCue is IEnumerable)
			{
				foreach (Type type in (visualCue as IEnumerable).OfType<Type>())
				{
					if (type.IsDefined(typeof(InterpolatedAttribute), false))
					{
						interpolatedVisual = type;
						break;
					}
				}
			}
			if (interpolatedVisual != null)
			{
				// Create InterpolatedVisuals list.
				Assembly parts = Assembly.GetAssembly(typeof(Item));// Parts assmebly
				Debug.Assert(parts != null, "parts != null", "Parts assembly must be already loaded");
				foreach (Type type in parts.GetExportedTypes())
				{
					if (type.IsDefined(typeof(InterpolatedAttribute), false))
						interpolatedVisuals.Add(type);
				}
			}

			itemDataView.PropertyChanged += propertyChanged;
			this.itemDataView = itemDataView;
			DataContext = itemDataView;
			this.PropertyChanged += propertyChanged;
		}

		/// <summary>
		/// Raises the <see cref="E:System.Windows.Window.Closed"/> event.
		/// </summary>
		/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
		protected override void OnClosed(EventArgs e)
		{
			base.OnClosed(e);

			this.PropertyChanged -= propertyChanged;
			itemDataView.PropertyChanged -= propertyChanged;
			DataContext = null;
		}

		#region ItemDataView
		ItemDataView itemDataView;
		public ItemDataView ItemDataView
		{
			get { return itemDataView; }
		}
		#endregion ItemDataView

		/// <summary>
		/// Enable OK button.
		/// Handles the PropertyChanged event of this dialog and the itemDataView object.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
		void propertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (string.IsNullOrEmpty((ItemDataView as IDataErrorInfo).Error))
				btnOK.IsEnabled = true;
			else
				btnOK.IsEnabled = false;
		}

		#region HorizontalScaleTabHeader
		object horizontalScaleTabHeader = "H-Scale";
		/// <summary>
		/// Gets or sets the horizontal scale tab header.
		/// </summary>
		/// <value>The horizontal scale tab header.</value>
		public object HorizontalScaleTabHeader
		{
			get { return horizontalScaleTabHeader; }
			set 
			{
				if (horizontalScaleTabHeader != value)
				{
					horizontalScaleTabHeader = value; 
					NotifyPropertyChanged("HorizontalScaleTabHeader");
				}
			}
		}
		#endregion HorizontalScaleTabHeader

		#region ShowHorizontalScaleProperties
		bool showHorizontalScaleProperties = true;
		/// <summary>
		/// Gets or sets a value indicating whether to show horizontal CharScale properties tab.
		/// </summary>
		/// <value><c>true</c> to show horizontal scale properties; otherwise, <c>false</c>.</value>
		public bool ShowHorizontalScaleProperties
		{
			get { return showHorizontalScaleProperties; }
			set
			{
				if (showHorizontalScaleProperties != value)
				{
					showHorizontalScaleProperties = value;
					NotifyPropertyChanged("ShowHorizontalScaleProperties");
				}
			}
		}
		#endregion ShowHorizontalScaleProperties

		#region CanChangeHorizontalScaleType
		bool canChangeHorizontalScaleType = true;
		/// <summary>
		/// Gets or sets a value indicating whether it's allowed to change Horizontal Scale Type.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if allowed; otherwise, <c>false</c>.
		/// </value>
		public bool CanChangeHorizontalScaleType
		{
			get { return canChangeHorizontalScaleType; }
			set
			{
				if (canChangeHorizontalScaleType != value)
				{
					canChangeHorizontalScaleType = value;
					NotifyPropertyChanged("CanChangeHorizontalScaleType");
				}
			}
		}
		#endregion CanChangeHorizontalScaleType

		#region VerticalScaleTabHeader
		object verticalScaleTabHeader = "V-Scale";
		/// <summary>
		/// Gets or sets the vertical scale tab header.
		/// </summary>
		/// <value>The vertical scale tab header.</value>
		public object VerticalScaleTabHeader
		{
			get { return verticalScaleTabHeader; }
			set
			{
				if (verticalScaleTabHeader != value)
				{
					verticalScaleTabHeader = value;
					NotifyPropertyChanged("VerticalScaleTabHeader");
				}
			}
		}
		#endregion VerticalScaleTabHeader

		#region ShowVerticalScaleProperties
		bool showVerticalScaleProperties = true;
		/// <summary>
		/// Gets or sets a value indicating whether to show Vertical CharScale properties tab.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if show Vertical scale properties; otherwise, <c>false</c>.
		/// </value>
		public bool ShowVerticalScaleProperties
		{
			get { return showVerticalScaleProperties; }
			set
			{
				if (showVerticalScaleProperties != value)
				{
					showVerticalScaleProperties = value;
					NotifyPropertyChanged("ShowVerticalScaleProperties");
				}
			}
		}
		#endregion ShowVerticalScaleProperties

		#region CanChangeVerticalScaleType
		bool canChangeVerticalScaleType = true;
		/// <summary>
		/// Gets or sets a value indicating whether it's allowed to change Vertical Scale Type.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if allowed; otherwise, <c>false</c>.
		/// </value>
		public bool CanChangeVerticalScaleType
		{
			get { return canChangeVerticalScaleType; }
			set
			{
				if (canChangeVerticalScaleType != value)
				{
					canChangeVerticalScaleType = value;
					NotifyPropertyChanged("CanChangeVerticalScaleType");
				}
			}
		}
		#endregion CanChangeVerticalScaleType

		#region ZScaleTabHeader
		object zScaleTabHeader = "Z-Scale";
		/// <summary>
		/// Gets or sets the Z scale tab header.
		/// </summary>
		/// <value>The Z scale tab header.</value>
		public object ZScaleTabHeader
		{
			get { return zScaleTabHeader; }
			set
			{
				if (zScaleTabHeader != value)
				{
					zScaleTabHeader = value;
					NotifyPropertyChanged("ZScaleTabHeader");
				}
			}
		}
		#endregion ZScaleTabHeader

		#region ShowZScaleProperties
		bool showZScaleProperties = true;
		/// <summary>
		/// Gets or sets a value indicating whether to show Z CharScale properties tab.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if show Z scale properties; otherwise, <c>false</c>.
		/// </value>
		public bool ShowZScaleProperties
		{
			get { return showZScaleProperties; }
			set
			{
				if (showZScaleProperties != value)
				{
					showZScaleProperties = value;
					NotifyPropertyChanged("ShowZScaleProperties");
				}
			}
		}
		#endregion ShowZScaleProperties

		#region CanChangeZScaleType
		/// <summary>
		/// Gets or sets a value indicating whether it's allowed to change Z Scale Type.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if allowed; otherwise, <c>false</c>.
		/// </value>
		public bool CanChangeZScaleType
		{
			get { return false; }
			set	{ }
		}
		#endregion CanChangeZScaleType

		#region InterpolatedVisual
		/// <summary>
		/// Gets the InterpolatedVisuals collection.
		/// </summary>
		/// <value>The visual cues.</value>
		List<Type> interpolatedVisuals = new List<Type>();
		public List<Type> InterpolatedVisuals 
		{
			get { return interpolatedVisuals; }
			private set
			{
				if (interpolatedVisuals != value)
				{
					interpolatedVisuals = value;
					NotifyPropertyChanged("InterpolatedVisuals");
				}
			}
		}

		Type interpolatedVisual;
		/// <summary>
		/// Gets or sets the Interpolated Visual type.
		/// </summary>
		/// <value>Interpolated Visual type.</value>
		public Type InterpolatedVisual
		{
			get { return interpolatedVisual; }
			set
			{
				if (interpolatedVisual != value)
				{
					interpolatedVisual = value;
					NotifyPropertyChanged("InterpolatedVisual");

					// Set ItemDataView.VisualCue value.
					object visualCue = ItemDataView.VisualCue;
					if (visualCue is Type && (visualCue as Type).IsDefined(typeof(InterpolatedAttribute), false))
					{
						ItemDataView.VisualCue = interpolatedVisual;
					}
					else if (visualCue is IList)
					{
						IList list = visualCue as IList;
						for (int i = 0; i < list.Count;i++)
						{
							Type type = list[i] as Type;
							if (type != null && type.IsDefined(typeof(InterpolatedAttribute), false))
							{
								list[i] = interpolatedVisual;
								break;
							}
						}
					}
				}
			}
		}
		#endregion InterpolatedVisual

		#region Commands
		#region SelectCurveColorCommand
		ICommand selectCurveColorCommand;
		/// <summary>
		/// Gets the SelectCurveColorCommand.
		/// </summary>
		/// <value/>
		public ICommand SelectCurveColorCommand
		{
			get
			{
				if (selectCurveColorCommand == null)
				{
					selectCurveColorCommand = new RelayCommand(selectCurveColor);
				}
				return selectCurveColorCommand;
			}
		}
		/// <summary>
		/// Selects the Curve color.
		/// </summary>
		private void selectCurveColor(object parameter)
		{
			CurveDataView curveDataView = ItemDataView as CurveDataView;
			if (curveDataView == null)
				return;
			Color color = Colors.Black;
			if (curveDataView.Pen != null)
			{
				SolidColorBrush brush = curveDataView.Pen.Brush as SolidColorBrush;
				if (brush != null)
					color = brush.Color;
			}
			
			ChooseColorDialog.ColorDialog dlg = new ChooseColorDialog.ColorDialog(color);
			if (dlg.ShowDialog() == true)
			{
				if (curveDataView.Pen != null)
					curveDataView.Pen.Brush = new SolidColorBrush(dlg.SelectedColor);
				else
					curveDataView.Pen = new Pen(new SolidColorBrush(dlg.SelectedColor), 1);
			}
		}
		#endregion SelectCurveColorCommand

		#region SelectAreaBrushCommand
		ICommand selectAreaBrushCommand;
		/// <summary>
		/// Gets the SelectAreaBrushCommand.
		/// </summary>
		/// <value/>
		public ICommand SelectAreaBrushCommand
		{
			get
			{
				if (selectAreaBrushCommand == null)
				{
					selectAreaBrushCommand = new RelayCommand(selectAreaBrush);
				}
				return selectAreaBrushCommand;
			}
		}
		/// <summary>
		/// Selects the AreaBrush.
		/// </summary>
		private void selectAreaBrush(object parameter)
		{
			CurveDataView curveDataView = ItemDataView as CurveDataView;
			if (curveDataView == null)
				return;
			Color color = Colors.Transparent;
			if (curveDataView.AreaBrush != null)
			{
				SolidColorBrush brush = curveDataView.AreaBrush as SolidColorBrush;
				if (brush != null)
					color = brush.Color;
			}
			
			ChooseColorDialog.ColorDialog dlg = new ChooseColorDialog.ColorDialog(color);
			if (dlg.ShowDialog() == true)
				curveDataView.AreaBrush = new SolidColorBrush(dlg.SelectedColor);
		}
		#endregion SelectAreaBrushCommand

		#region PointMarkerPropertiesCommand
		ICommand pointMarkerPropertiesCommand;
		/// <summary>
		/// Gets the PointMarkerPropertiesCommand.
		/// </summary>
		/// <value/>
		public ICommand PointMarkerPropertiesCommand
		{
			get
			{
				if (pointMarkerPropertiesCommand == null)
				{
					pointMarkerPropertiesCommand = new RelayCommand(pointMarkerProperties);
				}
				return pointMarkerPropertiesCommand;
			}
		}
		/// <summary>
		/// Set PointMarker Properties with the <see cref="PointMarkerDialog"/>.
		/// </summary>
		private void pointMarkerProperties(object parameter)
		{
			IPointMarker iPointMarker = ItemDataView as IPointMarker;
			if (iPointMarker == null)
				return;
			Color color = Colors.Transparent;
			GeometryDrawing drawing = iPointMarker.PointMarker as GeometryDrawing;
			if (drawing != null)
			{
				SolidColorBrush curveBrush = drawing.Brush as SolidColorBrush;
				if (curveBrush != null)
					color = curveBrush.Color;
			}
			PointMarkerDialog dlg = new PointMarkerDialog(color) { Owner = this };
			if (dlg.ShowDialog() == true)
			{
				iPointMarker.PointMarker = new GeometryDrawing(new SolidColorBrush(dlg.MarkerFillColor)
					, new Pen(new SolidColorBrush(dlg.MarkerStrokeColor), 1), dlg.MarkerGeometry);
			}
		}
		#endregion PointMarkerPropertiesCommand

		#region BubblePropertiesCommand
		ICommand bubblePropertiesCommand;
		/// <summary>
		/// Gets the BubblePropertiesCommand.
		/// </summary>
		/// <value/>
		public ICommand BubblePropertiesCommand
		{
			get
			{
				if (bubblePropertiesCommand == null)
				{
					bubblePropertiesCommand = new RelayCommand(bubbleProperties);
				}
				return bubblePropertiesCommand;
			}
		}
		/// <summary>
		/// Set Bubble Properties with the <see cref="PointMarkerDialog"/>.
		/// </summary>
		private void bubbleProperties(object parameter)
		{
			IBubble iBubble = ItemDataView as IBubble;
			if (iBubble == null)
				return;
			Color color = Colors.Transparent;
			GeometryDrawing drawing = iBubble.Bubble as GeometryDrawing;
			if (drawing != null)
			{
				SolidColorBrush curveBrush = drawing.Brush as SolidColorBrush;
				if (curveBrush != null)
					color = curveBrush.Color;
			}
			PointMarkerDialog dlg = new PointMarkerDialog(color) { Owner = this };
			if (dlg.ShowDialog() == true)
			{
				iBubble.Bubble = new GeometryDrawing(new SolidColorBrush(dlg.MarkerFillColor)
					, new Pen(new SolidColorBrush(dlg.MarkerStrokeColor), 1), dlg.MarkerGeometry);
			}
		}
		#endregion BubblePropertiesCommand

		#region SelectLabelBrushCommand
		ICommand selectLabelBrushCommand;
		/// <summary>
		/// Gets the SelectLabelBrushCommand.
		/// </summary>
		/// <value/>
		public ICommand SelectLabelBrushCommand
		{
			get
			{
				if (selectLabelBrushCommand == null)
				{
					selectLabelBrushCommand = new RelayCommand(selectLabelBrush);
				}
				return selectLabelBrushCommand;
			}
		}
		/// <summary>
		/// Selects the Label Brush.
		/// </summary>
		private void selectLabelBrush(object parameter)
		{
			IBubble iBubble = ItemDataView as IBubble;
			if (iBubble == null)
				return;
			Color color = Colors.Black;
			SolidColorBrush brush = iBubble.LabelBrush as SolidColorBrush;
			if (brush != null)
				color = brush.Color;
			
			ChooseColorDialog.ColorDialog dlg = new ChooseColorDialog.ColorDialog(color);
			if (dlg.ShowDialog() == true)
				iBubble.LabelBrush = new SolidColorBrush(color);
		}
		#endregion SelectLabelBrushCommand

		#region ChooseBubbleLabelFontCommand
		ICommand chooseBubbleLabelFontCommand;
		/// <summary>
		/// Gets the ChooseBubbleLabelFontCommand.
		/// </summary>
		/// <value/>
		public ICommand ChooseBubbleLabelFontCommand
		{
			get
			{
				if (chooseBubbleLabelFontCommand == null)
				{
					chooseBubbleLabelFontCommand = new RelayCommand(chooseBubbleLabelFont);
				}
				return chooseBubbleLabelFontCommand;
			}
		}
		/// <summary>
		/// Selects the Font with ChooseFont dialog.
		/// </summary>
		private void chooseBubbleLabelFont(object parameter)
		{
			IBubble iBubble = ItemDataView as IBubble;
			if (iBubble == null)
				return;
			ChooseFontDialog.ChooseFont dlg = new ChooseFontDialog.ChooseFont(
				new ChooseFontDialog.FontInfo()
				{
					FontFamily = iBubble.FontFamily,
					Typeface = new Typeface(iBubble.FontFamily, iBubble.FontStyle
						, iBubble.FontWeight, iBubble.FontStretch),
					FontSize = iBubble.FontSize
				});
			if (dlg.ShowDialog() == true)
			{
				ChooseFontDialog.FontInfo fi = dlg.FontInfo;
				iBubble.FontFamily = fi.FontFamily;
				iBubble.FontStyle = fi.Typeface.Style;
				iBubble.FontWeight = fi.Typeface.Weight;
				iBubble.FontStretch = fi.Typeface.Stretch;
				iBubble.FontSize = fi.FontSize;
			}
		}
		#endregion ChooseBubbleLabelFontCommand

		#region SelectColumnBrushCommand
		ICommand selectColumnBrushCommand;
		/// <summary>
		/// Gets the SelectColumnBrushCommand.
		/// </summary>
		/// <value/>
		public ICommand SelectColumnBrushCommand
		{
			get
			{
				if (selectColumnBrushCommand == null)
				{
					selectColumnBrushCommand = new RelayCommand(selectColumnBrush);
				}
				return selectColumnBrushCommand;
			}
		}
		/// <summary>
		/// Selects the Column Brush.
		/// </summary>
		private void selectColumnBrush(object parameter)
		{
			ColumnChartItemDataView columnDataView = ItemDataView as ColumnChartItemDataView;
			if (columnDataView == null)
				return;
			Color color = Colors.Black;
			SolidColorBrush brush = columnDataView.ColumnBrush as SolidColorBrush;
			if (brush != null)
				color = brush.Color;
			
			ChooseColorDialog.ColorDialog dlg = new ChooseColorDialog.ColorDialog(color);
			if (dlg.ShowDialog() == true)
				columnDataView.ColumnBrush = new SolidColorBrush(dlg.SelectedColor);

		}
		#endregion SelectColumnBrushCommand
		#endregion Commands

		/// <summary>
		/// Handles the Click event of the btnOK control.
		/// Applyes changes and closes.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		private void btnOK_Click(object sender, RoutedEventArgs e)
		{
			DialogResult = true;
		}

		#region INotifyPropertyChanged Members
		public event PropertyChangedEventHandler PropertyChanged;

		void NotifyPropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
			{
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
			}
		}
		#endregion INotifyPropertyChanged Members
	}
}
